﻿using System;
using System.Collections.Generic;
using System.Xml;
using System.IO;
using System.Text;
using System.Windows.Forms;

namespace FIS.iDET
{
    class XmlService
    {
        public static void ExportAddressNumber(string stringInput, out int col, out int row)
        {
            col = 0;
            row = 0;
            //foreach (char c in stringInput)
            int baseNumber = 0;
            string s1 = "";

            if (stringInput != "")
            {
                while (stringInput[0] >= 'A' && stringInput[0] <= 'Z')
                {
                    s1 = s1 + stringInput[0];
                    stringInput = stringInput.Remove(0, 1);
                }

                // Process col value
                while (s1.Length > 0)
                { 
                    col = col + ((int)s1[s1.Length - 1] - 64) * (int)Math.Pow(26, baseNumber);
                    s1 = s1.Remove(s1.Length - 1, 1);
                    baseNumber++;
                }

                // row value
                row = Convert.ToInt32(stringInput);
            }
            return;
        }

        public static void CalculateAddressNumber(string stringAdress, out int col, out int row1, out int row2)
        {
            col = 0;
            row1 = 0;
            row2 = 0; 
            int temp = 0;
            stringAdress = stringAdress.Trim();
            char[] delimiter = { ' ' };
            string[] pieces = stringAdress.Split(delimiter, 2, StringSplitOptions.None);
            pieces[0] = pieces[0].Trim();
            if (pieces.Length > 1)
                pieces[1] = pieces[1].Trim();
            
            // first is  1st Cell
            ExportAddressNumber(pieces[0], out col, out row1);
            // second is 2nd Cell
            if (pieces.Length > 1)
                ExportAddressNumber(pieces[1], out temp, out row2);

            return;
        }

        public static void CalculateColNumber(string s, out int col)
        {
            int baseNumber = 0;
            col = 0;
            if (s != "")
            {
                // Process col value
                s = s.ToUpper();
                while (s.Length > 0)
                {
                    col = col + ((int)s[s.Length - 1] - 64) * (int)Math.Pow(26, baseNumber);
                    s = s.Remove(s.Length - 1, 1);
                    baseNumber++;
                }
            }
        }
        
        public static List<int> ConvertToPageNumbers(string s)
        {
            List<int> result = new List<int>();
            char[] delimiter = { ',' };
            string[] parts = s.Split(delimiter, StringSplitOptions.RemoveEmptyEntries);
            for (int i = 0; i < parts.Length; i++)
            {
                int num = 0;
                if (Int32.TryParse(parts[i], out num))
                {
                    result.Add(num);
                }
                else
                    MessageBox.Show("Please check again !\nWrong in identify page number:" + parts[i].ToString());
            }
            return result;
        }

        public static List<DataColumn> ReadPageCompareXML(string fromFile, out PageCompareInfo pageAll, out List<PageCompareInfo> listPages)
        {
            pageAll = new PageCompareInfo();
            listPages = new List<PageCompareInfo>();
            try
            {
                FileStream fs = new FileStream(fromFile, FileMode.Open,FileAccess.Read, FileShare.ReadWrite);
                XmlDocument r = new XmlDocument();
                r.Load(fs);
                
                // array to store field data
                List<DataColumn> columns = new List<DataColumn>();

                // PAGEALL NODE

                XmlNode pageAllNode = r.SelectSingleNode("//form/pageall");
                
                // Read Start Row & End Row
                Int32.TryParse(pageAllNode.Attributes["startrow"].InnerText, out pageAll.startRow);
                if (pageAllNode.Attributes["endrow"] != null)
                    Int32.TryParse(pageAllNode.Attributes["endrow"].InnerText, out pageAll.endRow);
                else
                    pageAll.endRow = 0;
                
                for (int i = 0; i < pageAllNode.ChildNodes.Count; i++)
                {
                    // Create new ColumnCompareInfo
                    ColumnCompareInfo colCompare = new ColumnCompareInfo();

                    // MODE
                    
                    // add an column to file result !
                    if (pageAllNode.ChildNodes[i].Attributes["mode"] == null)
                    {
                        colCompare.fieldName = pageAllNode.ChildNodes[i].Attributes["fieldname"].InnerText;
                        colCompare.mode = CompareMode.NONE;
                        pageAll.listColumnCompare.Add(colCompare);
                        columns.Add(new DataColumn(pageAllNode.ChildNodes[i].Attributes["fieldname"].InnerText));
                        continue;
                    }
                        
                    if (pageAllNode.ChildNodes[i].Attributes["mode"].InnerText == "compare")
                    {
                        // Add value to    
                        colCompare.mode = CompareMode.COMPARE;
                    }
                    else
                    {
                        colCompare.mode = CompareMode.DISPLAY;
                        if (pageAllNode.ChildNodes[i].Attributes["source"].InnerText == "file1")
                            colCompare.source = FileSource.FILE1;
                        else
                            colCompare.source = FileSource.FILE2;
                    }
                    
                    // FieldName
                    colCompare.fieldName = pageAllNode.ChildNodes[i].Attributes["fieldname"].InnerText;
                    
                    // column 
                    CalculateColNumber(pageAllNode.ChildNodes[i].Attributes["colname"].InnerText.Trim(), out colCompare.column);
                    // identify maxcolumn of excel data to read into memory
                    if (colCompare.column > GlobalVariables.lastColumn)
                        GlobalVariables.lastColumn = colCompare.column;

                    // CalculateAddressNumber(pageAllNode.ChildNodes[i].InnerText, out colCompare.column, out colCompare.startRow, out colCompare.endRow);

                    // Add columnInfo to page All 

                    pageAll.listColumnCompare.Add(colCompare);

                    // Add field to GridView
                    columns.Add(new DataColumn(pageAllNode.ChildNodes[i].Attributes["fieldname"].InnerText));
                }
                
                // Process OTHER PAGE NODES
                XmlNodeList pagesNode = r.GetElementsByTagName("page");

                // Process all page nodes
                for (int i = 0; i < pagesNode.Count; i++)
                {
                    List<int> pageNumbers = new List<int>(ConvertToPageNumbers(pagesNode[i].Attributes["number"].InnerText));
                    for (int m = 0; m < pageNumbers.Count; m++)
                    {
                        PageCompareInfo page = new PageCompareInfo();
                        page.pageID = pageNumbers[m];
                        
                        // Assign Start row & End row to page
                        Int32.TryParse(pagesNode[i].Attributes["startrow"].InnerText, out page.startRow);
                        if (pagesNode[i].Attributes["endrow"] != null)
                        {
                            Int32.TryParse(pagesNode[i].Attributes["endrow"].InnerText, out page.endRow);
                        }
                        else
                            page.endRow = 0;

                        // Process per page
                        for (int j = 0; j < pagesNode[i].ChildNodes.Count; j++)
                        {
                            // Create new ColumnCompareInfo
                            ColumnCompareInfo colCompare = new ColumnCompareInfo();

                            // identify Mode

                            if (pagesNode[i].ChildNodes[j].Attributes["mode"] == null)
                            {
                                colCompare.fieldName = pagesNode[i].ChildNodes[i].Attributes["fieldname"].InnerText;
                                colCompare.mode = CompareMode.NONE;
                                page.listColumnCompare.Add(colCompare);
                                continue;
                            }
                            
                            if (pagesNode[i].ChildNodes[j].Attributes["mode"].InnerText == "compare")
                            {
                                // Add value to    
                                colCompare.mode = CompareMode.COMPARE;
                            }
                            else
                            {
                                colCompare.mode = CompareMode.DISPLAY;
                                if (pagesNode[i].ChildNodes[j].Attributes["source"].InnerText == "file1")
                                    colCompare.source = FileSource.FILE1;
                                else
                                    colCompare.source = FileSource.FILE2;
                            }
                            // Field name
                            colCompare.fieldName = pagesNode[i].ChildNodes[j].Attributes["fieldname"].InnerText;

                            // Column 
                            CalculateColNumber(pagesNode[i].ChildNodes[j].Attributes["colname"].InnerText.Trim(), out colCompare.column);
                            // identify maxcolumn of excel data to read into memory
                            if (colCompare.column > GlobalVariables.lastColumn)
                                GlobalVariables.lastColumn = colCompare.column;

                            //CalculateAddressNumber(pagesNode[i].ChildNodes[j].InnerText, out colCompare.column, out colCompare.startRow, out colCompare.endRow);
                            // Add column to pages                                                
                            page.listColumnCompare.Add(colCompare);
                        }
                        listPages.Add(page);
                    }
                }

                // process charsRemove Node
                XmlNode charsRemoveNode = r.SelectSingleNode("//form/remove");
                if (charsRemoveNode != null)
                    GlobalVariables.charsRemove = charsRemoveNode.Attributes["chars"].Value.ToString();
                
                // Upgrade: Remove attribute moved to form tag
                XmlNode formNode = r.SelectSingleNode("//form");
                if (formNode.Attributes["removecharacters"] != null)
                {
                    GlobalVariables.charsRemove = formNode.Attributes["removecharacters"].InnerText.ToString();
                }

                fs.Close();
                return columns;
            }
            catch (Exception ex)
            {
                MessageBox.Show("Unexpected error while loading template file \"" + fromFile + "\"\nError details: " + ex.Message);
                return null;
            }
        }

        public static bool ReadXml(string fromFile)
        {
            try
            {
                FileStream fs = new FileStream(fromFile, FileMode.Open);
                XmlTextReader r = new XmlTextReader(fs);

                // get root node
                //r.Read(); // <?xml version="1.0" encoding="utf-8"?>
                while (r.Read())
                {
                    if (r.NodeType == XmlNodeType.Element && r.Name == "template")
                    {
                        // set template properties to global vars
                        //GlobalConstants.TemplateName = r.GetAttribute("name");
                        GlobalConstants.TemplateZoom = Convert.ToDouble(r.GetAttribute("zoom")) / 100;
                        GlobalConstants.TemplateVersion = r.GetAttribute("version");
                        GlobalConstants.TemplatePageCol = Convert.ToInt32(r.GetAttribute("pagecol"));
                        break;
                    }
                }

                // array to store processed data
                List<DataColumn> columns = new List<DataColumn>();
                GlobalConstants.ColumnsOriginalRects = new List<DoubleRectangle>();

                // read column nodes
                while (r.Read())
                {
                    // get header text from current node's name
                    if (r.NodeType == XmlNodeType.Element && r.Name == "col")
                    {
                        double x = Convert.ToDouble(r.GetAttribute("x"));
                        double y = Convert.ToDouble(r.GetAttribute("y"));
                        double w = Convert.ToDouble(r.GetAttribute("w"));
                        double h = Convert.ToDouble(r.GetAttribute("h"));

                        columns.Add(
                            new DataColumn(
                                r.GetAttribute("fieldname"),
                                Convert.ToInt32(r.GetAttribute("datatype")),
                                Convert.ToInt32(r.GetAttribute("colwidth")),
                                x, y, w, h));

                        GlobalConstants.ColumnsOriginalRects.Add(new DoubleRectangle(x, y, w, h));

                    }
                    // no need to read for text node since we use none of these in our template
                    /*
                    else if (r.NodeType == XmlNodeType.Text)
                    {
                    Console.WriteLine("\tVALUE: " + r.Value);
                    }
                    */
                }

                // set template's columns info to global vars
                GlobalConstants.Columns = columns;

                fs.Close();

                return true;
            }
            catch (Exception ex)
            {
                MessageBox.Show("Unexpected error while loading template file \"" + fromFile + "\"\nError details: " + ex.Message);
                return false;
            }
        }

        public static string getDataTypeShortNameOf(string longName)
        {
            if (longName == "Date Time")
                return DataTypeEnum.COLUMN_TYPE_DATE.ToString();
            else if (longName == "Number")
                return DataTypeEnum.COLUMN_TYPE_NUMBER.ToString();
            else
                return DataTypeEnum.COLUMN_TYPE_TEXT.ToString();
        }

        public static string getDataTypeLongNameOf(int shortName)
        {
            switch (shortName)
            {
                case DataTypeEnum.COLUMN_TYPE_DATE:
                    return "Date Time";
                case DataTypeEnum.COLUMN_TYPE_NUMBER:
                    return "Number";
                default:
                    return "General Text";
            }
        }
    }
}